package qrcode;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.ImageIO;

import com.swetake.util.Qrcode;

public class QrcodeWithLogo {
	/** 
     * 生成二维码(QRCode)图片 
     * @param content 二维码图片的内容
     * @param imgPath 生成二维码图片完整的路径
     * @param ccbpath  二维码图片中间的logo路径
     */  
    public static int createQRCode(String content, String imgPath,String ccbPath) {  
        try {  
            Qrcode qrcodeHandler = new Qrcode();  
            qrcodeHandler.setQrcodeErrorCorrect('H');  
            qrcodeHandler.setQrcodeEncodeMode('B');  
            qrcodeHandler.setQrcodeVersion(7);  
  
            // System.out.println(content);  
            byte[] contentBytes = content.getBytes("gb2312");  
            BufferedImage bufImg = new BufferedImage(139, 139, BufferedImage.TYPE_INT_RGB);  
            Graphics2D gs = bufImg.createGraphics();  
  
            gs.setBackground(Color.WHITE);  
            gs.clearRect(0, 0, 139, 139);  
  
            // 设定图像颜色 > BLACK  
            gs.setColor(Color.ORANGE);  
  
            // 设置偏移量 不设置可能导致解析出错  
            int pixoff = 2;  
            // 输出内容 > 二维码  
            if (contentBytes.length > 0 && contentBytes.length < 120) {  
                boolean[][] codeOut = qrcodeHandler.calQrcode(contentBytes);  
                for (int i = 0; i < codeOut.length; i++) {  
                    for (int j = 0; j < codeOut.length; j++) {  
                        if (codeOut[j][i]) {  
                            gs.fillRect(j * 3 + pixoff, i * 3 + pixoff, 3, 3);  
                        }  
                    }  
                }  
            } else {  
                System.err.println("QRCode content bytes length = "  
                        + contentBytes.length + " not in [ 0,120 ]. ");  
                return -1;
            }  
            Image img = ImageIO.read(new File(ccbPath));//实例化一个Image对象。
            gs.drawImage(img, 45, 45, null);
            gs.dispose();  
            bufImg.flush();  
  
            // 生成二维码QRCode图片  
            File imgFile = new File(imgPath);  
            ImageIO.write(bufImg, "png", imgFile);  
  
        } catch (Exception e) 
        {  
            e.printStackTrace();  
            return -100;
        }  
        
        return 0;
       }
    
    public static void main(String[] args) {
    	QrcodeWithLogo logo=new QrcodeWithLogo();
    	logo.createQRCode("王代军", "D:/wdjQH.png", "D:/q.jpg");
	}
}  


/**   二维码(2-dimensional bar code)，是用某种特定的几何图形按照一定规律在平面分布的黑白相间的图形记录数据符合信息的。
     常用到的码制有：Data Matrix , Maxi Code , Aztec , QR Code , Vericode , PDF417 , Ultracode , Code 49 , Code 16K等
     ①：堆叠式/行排式二维条码，如，Code 16K、Code 49、PDF417（如下图）等

 ②：矩阵式二维码，最流行莫过于QR CODE
             二维码存储的数据量更大；可以包含数字、字符，及中文文本等混合内容；有一定的容错性（在部分损坏以后可以正常读取）；空间利用率高等。
     ③：QR CODE 介绍
    
如上图时一个qrcode的基本结构，其中：
位置探测图形、位置探测图形分隔符、定位图形：用于对二维码的定位，对每个QR码来说，位置都是固定存在的，只是大小规格会有所差异；
校正图形：规格确定，校正图形的数量和位置也就确定了；
格式信息：表示改二维码的纠错级别，分为L、M、Q、H；

版本信息：即二维码的规格，QR码符号共有40种规格的矩阵（一般为黑白色），从21x21（版本1），到177x177（版本40），每一版本符号比前一版本 每边增加4个模块。
数据和纠错码字：实际保存的二维码信息，和纠错码字（用于修正二维码损坏带来的错误）。

简要的编码过程：
    1. 数据分析：确定编码的字符类型，按相应的字符集转换成符号字符； 选择纠错等级，在规格一定的条件下，纠错等级越高其真实数据的容量越小。

2. 数据编码：将数据字符转换为位流，每8位一个码字，整体构成一个数据的码字序列。其实知道这个数据码字序列就知道了二维码的数据内容。

            数据可以按照一种模式进行编码，以便进行更高效的解码，例如：对数据：01234567编码（版本1-H），
             1）分组：012 345 67
             2）转成二进制：012→0000001100
                                                   345→0101011001
                                                    67 →1000011
              3）转成序列：0000001100 0101011001 1000011
              4）字符数 转成二进制：8→0000001000
              5）加入模式指示符（上图数字）0001：0001 0000001000 0000001100 0101011001 1000011
           对于字母、中文、日文等只是分组的方式、模式等内容有所区别。基本方法是一致的

 3. 纠错编码：按需要将上面的码字序列分块，并根据纠错等级和分块的码字，产生纠错码字，并把纠错码字加入到数据码字序列后面，成为一个新的序列。

    在二维码规格和纠错等级确定的情况下，其实它所能容纳的码字总数和纠错码字数也就确定了，比如：版本10，纠错等级时H时，总共能容纳346个码字，其中224个纠错码字。
        就是说二维码区域中大约1/3的码字时冗余的。对于这224个纠错码字，它能够纠正112个替代错误（如黑白颠倒）或者224个据读错误（无法读到或者无法译码），
        这样纠错容量为：112/346=32.4%
      
    4. 构造最终数据信息：在规格确定的条件下，将上面产生的序列按次序放如分块中
        按规定把数据分块，然后对每一块进行计算，得出相应的纠错码字区块，把纠错码字区块 按顺序构成一个序列，添加到原先的数据码字序列后面。
        如：D1, D12, D23, D35, D2, D13, D24, D36, ... D11, D22, D33, D45, D34, D46, E1, E23,E45, E67, E2, E24, E46, E68，...

构造矩阵：将探测图形、分隔符、定位图形、校正图形和码字模块放入矩阵中。

5. 把上面的完整序列填充到相应规格的二维码矩阵的区域中


    6. 掩摸：将掩摸图形用于符号的编码区域，使得二维码图形中的深色和浅色（黑色和白色）区域能够比率最优的分布。
             一个算法，不研究了，有兴趣的同学可以继续。
    7. 格式和版本信息：生成格式和版本信息放入相应区域内。
        版本7-40都包含了版本信息，没有版本信息的全为0。二维码上两个位置包含了版本信息，它们是冗余的。
        版本信息共18位，6X3的矩阵，其中6位时数据为，如版本号8，数据位的信息时 001000，后面的12位是纠错位。


 * */
